/**
 * MenuViewActivity.java
 * @author Marco Secchiero
 * 
 * This activity is the core of the application. It realizes all client-side
 * logic implemented by ConnectionManager and ManagerStaticBuilder classes.
 * The menu is an ExpandableListView where for each category shows the
 * items available. 
 * Each item can be ordered by selecting and long-pressing it to increase 
 * (or decrease) the quantity.
 * Finally the total order is sent to the server by a menu-button.
 */

package wfta.client.gui;

import java.io.Serializable;
import java.util.Vector;

import wfta.client.ConnectionManager;
import wfta.client.ConnectionStatus;
import wfta.client.ManagerStaticBuilder;
import wfta.common.Item;
import wfta.client.MessageType;
import android.app.Dialog;
import android.app.ExpandableListActivity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ExpandableListView;
import android.widget.TextView;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;


public class MenuViewActivity extends ExpandableListActivity {

	// menu item constants
	private static final int MENU_SEND = 0;
	private static final int MENU_EXIT = 1;
	private static final int INC_QTY = 0;
	private static final int DEC_QTY = 1;
	private static final int GET_DESC = 2;
	private static final int ESC = 3;
	private static final int DIALOG_SEND_ORDER = 0;
	private static final int DIALOG_EXIT = 1;
	private static final int PROGRESS_DIALOG = 2;
	private static final int ERROR_DIALOG = 3;
	private static MenuItem MENU_ITEM;


	/**
	 * the progress thread
	 */
	private ProgressThread progrThread = null;

	/**
	 *  the connection
	 */
	private ConnectionManager _manager;

	/**
	 * the expandable list
	 */
	private MyExpList _expList;

	/**
	 * the TextView of the status of the sending 
	 */
	private TextView messagesLst;
	
	private boolean resetted = false;

	/**
	 * Handler that reads and shows on a Dialog all informative and error 
	 * messages received from the server
	 */
	final Handler handlerSend = new Handler() {
		public void handleMessage(Message msg) {
			if (_manager.IsServerConnected() == ConnectionStatus.ERROR_DISCONECTED) {
				// something gone wrong
				messagesLst.setText("ERROR! Server unreachable!");
				resetted = true;
			} else {
				Vector<String> info_messages = (Vector<String>) msg.getData().getSerializable("info");
				Vector<String> err_messages = (Vector<String>) msg.getData().getSerializable("err");
				if (err_messages != null) {
					for (String m: err_messages){
						messagesLst.append(m+'\n');
					}
					_manager.ResetConfiguration();
				}
				else for (String m: info_messages){
					messagesLst.append(m+'\n');
				}
			}
		}
	};

	/** 
	 * Nested class that performs progress calculations (counting)
	 * @author Marco Secchiero 
	 */
	private class ProgressThread extends AsyncTask {
		private int idDialog;
		private int total;

		/**
		 * Constructor
		 * @param h - the Handler that manages all progress' comunication 
		 */
		public ProgressThread(int i) {
			idDialog = i;
		}


		@Override
		protected Object doInBackground(Object... params) {
			// TODO Auto-generated method stub
			try {   
				total = 0;
				while (total < 100) {
					Thread.sleep(10);
					total++;
				}
			} catch (Exception e) {
				showDialog(ERROR_DIALOG);
			}
			return null;
		}

		/**
		 * Called when the method doInBackground is terminated
		 */
		@Override
		protected void onPostExecute(Object result) {
			this.cancel(true);
			removeDialog(PROGRESS_DIALOG);
			showDialog(idDialog);
		}
	}

	/**
	 * Nested class that listens for server messages and shows them in a Dialog
	 * @author Marco Secchiero
	 */
	private class SendThread extends AsyncTask {
		private TextView messagesLst;
		private Handler mHandler;

		public SendThread(Handler h) {
			mHandler = h;
		}

		@Override
		protected Object doInBackground(Object... arg0) {
			// TODO Auto-generated method stub
			Vector<String> err_messages = null;
			Vector<String> info_messages = null;
			MenuViewActivity.this.messagesLst.setText("Order total price: "+_manager.GetTotalPrice()+"€\n");
			while (_manager.IsServerConnected()==ConnectionStatus.CONNECTED 
					&& err_messages==null) {
				// distinguish informative messages from error messages
				info_messages = _manager.GetUnreadedMessages(MessageType.INFORMATIVE);
				if (_manager.ThereAreErrors())
					err_messages = _manager.GetUnreadedMessages(MessageType.ERROR);

				/*
				 * set the handler to the object (Message) containing all information
				 * to print on the send dialog
				 */
				Message msg = mHandler.obtainMessage();
				Bundle b = new Bundle();
				b.putSerializable("info", info_messages);
				b.putSerializable("err", err_messages);
				b.putSerializable("textview", (Serializable) messagesLst);
				msg.setData(b);
				mHandler.sendMessage(msg);
			}


			// check if there are unread messages
			if (_manager.IsServerConnected() == ConnectionStatus.CLOSED_BY_SERVER ||
					_manager.IsServerConnected() == ConnectionStatus.ERROR_DISCONECTED){

				info_messages = _manager.GetUnreadedMessages(MessageType.INFORMATIVE);
				Message msg = mHandler.obtainMessage();
				Bundle b = new Bundle();
				b.putSerializable("info", info_messages);
				b.putSerializable("err", err_messages);
				b.putSerializable("textview", (Serializable) messagesLst);
				msg.setData(b);
				mHandler.sendMessage(msg);

				// disable menu item
				if (_manager.IsServerConnected() == ConnectionStatus.CLOSED_BY_SERVER)
					MENU_ITEM.setEnabled(false);
			}
			return messagesLst;
		}
	}

	/**
	 * Dialog's button OnClickListener
	 * @author Marco Secchiero
	 *
	 */
	protected class OKListener implements OnClickListener {
		private int id;

		public OKListener(int id) {
			this.id = id;
		}

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			removeDialog(id);
			if (id == DIALOG_EXIT){
				_manager.OnClose();
				finish();
			}
		}
	}

	/**
	 * Dialog's button OnClickListener
	 * @author Marco Secchiero
	 */
	protected class OnGeneralListener implements OnClickListener {
		private Dialog dialog;
		public OnGeneralListener(Dialog d) {
			dialog = d;
		}

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			dialog.dismiss();
		}

	}

	/**
	 * Dialog's button OnClickListener to exit
	 * @author Marco Secchiero
	 *
	 */
	protected class OKExitListener implements OnClickListener {
		private Dialog dialog;

		public OKExitListener(Dialog dialog) {
			this.dialog = dialog;
		}

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			removeDialog(DIALOG_EXIT);
			_manager.OnClose();
			finish();

		}
	}


	/**
	 * This method is called when a dialog is created
	 * @param id: identifies a choice
	 * @return the dialog
	 */
	protected Dialog onCreateDialog(int id) {
		//if (progrDialog != null) progrDialog.dismiss();

		Dialog dialog = new Dialog(this);
		dialog.setContentView(wfta.client.R.layout.dialog);

		// creates the button and assigns it to the dialog
		Button okBtn = (Button) dialog.findViewById(wfta.client.R.id.button);
		okBtn.setText("Ok");
		switch(id) {
		case DIALOG_SEND_ORDER:
			// called when "Send Order" is selected from the menu button
			okBtn.setOnClickListener(new OKListener(DIALOG_SEND_ORDER));
			dialog.setTitle("Sending details...");
			messagesLst = (TextView) dialog.findViewById(wfta.client.R.id.text);
			new SendThread(handlerSend).execute();
			return dialog;

		case DIALOG_EXIT:
			// called when "Exit" is selected from the menu button
			okBtn.setOnClickListener(new OKListener(DIALOG_EXIT));
			dialog.setTitle("Exit Application");
			TextView message = (TextView) dialog.findViewById(wfta.client.R.id.text);
			message.setText("Thanks and have a nice meal! Goodbye!");
			return dialog;
		case PROGRESS_DIALOG:
			// launch a progress dialog
			ProgressDialog progrDialog = new ProgressDialog(this);
			progrDialog.setMessage("Sending order...");
			progrDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
			progrThread = new ProgressThread(DIALOG_SEND_ORDER);
			progrThread.execute();	
			return progrDialog;

		case ERROR_DIALOG:
			// called to notify a connection error to the user
			dialog.setTitle("Error!");
			TextView messages = (TextView) dialog.findViewById(wfta.client.R.id.text);
			messages.setText("Connection Error!");
			return dialog;
		}
		return null;
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(wfta.client.R.layout.main);
		try {
			_manager = ManagerStaticBuilder.GetLastConnection();
			_expList = new MyExpList(this);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			showDialog(ERROR_DIALOG);
		}
		setListAdapter( _expList.getExpandableListAdapter());
		registerForContextMenu(getExpandableListView());
	}

	/**
	 * Creates the menu by adding menu items
	 * @param menu: the menu
	 */
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(0,MENU_SEND,0,"Send order");
		menu.add(0,MENU_EXIT,0,"Exit");
		return true;
	}

	/**
	 * Defines action to perform on option item selection
	 * @param item: a MenuItem
	 */
	public boolean onOptionsItemSelected(MenuItem item) {
		switch(item.getItemId()) {
		case MENU_SEND:
			try {
				/*
				 *  send orders and show the progress dialog, when it's completed
				 *  a dialog contained sending details is shown to the user
				 */

				// useful for disable the menu item at the end of the sending
				MENU_ITEM = item;
				if (resetted) _manager.ResetConnection();
				if (_expList.getQtyOrdered()>0) {
					// be sure that the user has selected one or more items
					_manager.SendOrders();
					showDialog(PROGRESS_DIALOG);
				}
				return true;
			} catch (Exception e) {
				// TODO Auto-generated catch block
				showDialog(ERROR_DIALOG);
			}
		case MENU_EXIT:
			/*
			 * launch a progress dialog, when it's completed disconnect the client
			 * and close the application
			 */
			ProgressDialog progrDialog = new ProgressDialog(this);
			progrDialog.setMessage("Disconnecting...");
			progrDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
			progrDialog.show();
			progrThread = new ProgressThread(DIALOG_EXIT);
			progrThread.execute();	
			return true;
		}
		return false;
	}

	/**
	 * Creates a context menu by long pressing an expandable list item
	 * @param menu: the menu
	 * @param v: the view
	 * @param menuInfo: the context menu information
	 */
	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
		ExpandableListContextMenuInfo info = 
			(ExpandableListContextMenuInfo)menuInfo;
		// show the context menu only if a child (menu item) is selected, not a category
		if (ExpandableListView.getPackedPositionChild(info.packedPosition)>=0) {
			super.onCreateContextMenu(menu, v, menuInfo);
			menu.add(0, INC_QTY, 0, "Increase quantity to order");
			menu.add(0, DEC_QTY, 0, "Decrease quantity to order");
			menu.add(0, GET_DESC,0, "Item Description");
			menu.add(0, ESC, 0, "Back");	
		}
	}

	/**
	 * Actions perform when menu item of context menu are selected
	 * @param item: the menu item
	 */
	public boolean onContextItemSelected(MenuItem item) {
		ExpandableListContextMenuInfo info = 
			(ExpandableListContextMenuInfo)item.getMenuInfo();
		switch(item.getItemId()) {
		case INC_QTY:
			// Increments quantity to order
			_expList.incrementQuantity(ExpandableListView.getPackedPositionGroup(info.packedPosition),
					ExpandableListView.getPackedPositionChild(info.packedPosition));
			_manager.IncrementOrder(
					(int) _expList.getExpandableListAdapter().getChildId(
							ExpandableListView.getPackedPositionGroup(info.packedPosition),
							ExpandableListView.getPackedPositionChild(info.packedPosition)));
			return true;
		case DEC_QTY:
			// Decrements quantity to order
			_expList.decrementQuantity(ExpandableListView.getPackedPositionGroup(info.packedPosition),
					ExpandableListView.getPackedPositionChild(info.packedPosition));
			_manager.DecrementOrder(
					(int) _expList.getExpandableListAdapter().getChildId(
							ExpandableListView.getPackedPositionGroup(info.packedPosition),
							ExpandableListView.getPackedPositionChild(info.packedPosition)));
			return true;
		case GET_DESC:
			// Shows item description
			Dialog dialog = new Dialog(this);
			dialog.setContentView(wfta.client.R.layout.dialog);

			// creates the button and assigns it to the dialog
			Button okBtn = (Button) dialog.findViewById(wfta.client.R.id.button);
			okBtn.setText("Ok");
			okBtn.setOnClickListener(new OnGeneralListener(dialog));

			dialog.setTitle("Item Description");
			TextView text = (TextView) dialog.findViewById(wfta.client.R.id.text);
			Item child = (Item) _expList.getExpandableListAdapter().getChild(
					ExpandableListView.getPackedPositionGroup(info.packedPosition),
					ExpandableListView.getPackedPositionChild(info.packedPosition));
			text.setText(child.getDescription());
			dialog.show();
			return true;
		case ESC:
			return true;
		}
		return false;
	}

}
